﻿using System;
using System.Collections.Generic;
using CoreEx.Common.Proxy;
using CoreEx.DynamicInvoker;
using LinFu.AOP.Interfaces;
using LinFu.IoC.Configuration;
using LinFu.IoC.Interfaces;
using LinFu.IoC;
using LinFu.Proxy;
using LinFu.Proxy.Interfaces;

namespace CoreEx.Common.Implementation.Proxy
{
    [Implements(typeof(IDynamicProxyFactory),LifecycleType.Singleton)]
    public class DynamicProxyFactory : IDynamicProxyFactory,IInitialize
    {
        private IServiceContainer _serviceContainer;
        
        public Type CreateProxyType(IProxyFactory proxyFactory, Type baseType, IEnumerable<Type> baseInterfaces, IConstructorInterceptor interceptor)
        {
            var targetProxyFactory = (ProxyFactory)proxyFactory;

            //Get a IInvokeWrapper instance to intercept calls to the actual IProxyBuilder instance
            var proxyBuilderInterceptor = _serviceContainer.GetService<IInvokeWrapper>("ProxyBuilderInterceptor", targetProxyFactory.ProxyBuilder);


            //Get a IInvokeWrapper instance to intercept calls to the actual IMethodBuilder instance
            var proxyMethodBuilderInterceptor = _serviceContainer.GetService<IInvokeWrapper>("ProxyMethodBuilderInterceptor",
                                                                                  ((ProxyBuilder)targetProxyFactory.ProxyBuilder).ProxyMethodBuilder);

            //Create the proxy to replace the original IProxyBuilder implementation.
            var proxyBuilderProxy = proxyFactory.CreateProxy<IProxyBuilder>(proxyBuilderInterceptor, new Type[] { });

            //Create the proxy to replace the original IMethodBuilder implementation.
            ((ProxyBuilder)targetProxyFactory.ProxyBuilder).ProxyMethodBuilder =
                proxyFactory.CreateProxy<IMethodBuilder>(proxyMethodBuilderInterceptor, new Type[] { });

            //Replace original implementation with a IProxyBuilder proxy instance        
            targetProxyFactory.ProxyBuilder = proxyBuilderProxy;

            //Create the proxy type
            Type proxyType = proxyFactory.CreateProxyType(baseType, baseInterfaces);

            //Assign the IConstructorInterceptor
            proxyType.DynamicInvoke("ConstructorInterceptor", interceptor);

            return proxyType;
        }

        public void Initialize(IServiceContainer source)
        {
            _serviceContainer = source;
        }
    }
}
